{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "nteract": {
          "transient": {
            "deleting": false
          }
        }
      },
      "source": [
        "# Repeat-Until-Success Sample\n",
        "This sample shows the use of branching on measurement and qubit reuse to implement a Repeat-Until-Success algorithm on Quantinuum hardware targets. It is drawn from a collaboration between Microsoft and Quantinuum research teams, specifically the authors Natalie C. Brown, John Peter Campora III, Ciarán Ryan-Anderson, Dominic Lucchetti, and Alex Chernoguzov from Quantinuum; Stefan Wernli, Adam Paetznick, Martin Roetteler, and Krysta Svore from Microsft; as well as Bettina Heim and Cassandra Granade.\n",
        "\n",
        "The program uses RUS and two sub-circuits to perform the single-qubit unitary V<sub>3</sub> = (I + 2iZ)/(√5) as described in detail in [Repeat-Until-Success: Non-deterministic decomposition of single-qubit unitaries](https://arxiv.org/abs/1311.1074) by Adam Paetznik and Krysta Svore.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "nteract": {
          "transient": {
            "deleting": false
          }
        }
      },
      "source": [
        "## 1. Connect to Azure Quantum and set up target\n",
        "\n",
        "First, we must configure the qsharp module to connect the azure workspace and specify a target. The Quantinuum H1 emulator target `quantinuum.sim.h1-1e` is chosen by default, which performs hardware-modeled noisy simulation. Running the experiments in this notebook against that target will consume approximately 25 HQC.\n",
        "\n",
        "We also configure the target capability as `AdaptiveExecution` to indicate we use the QIR profile with support for mid-circuit measurement, measurement-based control flow, and classical value support as part of compilation.\n",
        "\n",
        "Replace the `resourceId` and `location` connection parameters with the values for your configured Azure Quantum Workspace"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "jupyter": {
          "outputs_hidden": false,
          "source_hidden": false
        },
        "nteract": {
          "transient": {
            "deleting": false
          }
        }
      },
      "outputs": [],
      "source": [
        "import time\n",
        "import qsharp\n",
        "import qsharp.azure\n",
        "\n",
        "# Set the compiler target to the one queried from the workspace\n",
        "targets = qsharp.azure.connect(\n",
        "   resourceId=\"\",\n",
        "   location=\"\"\n",
        ")\n",
        "\n",
        "\n",
        "qsharp.azure.target(\"quantinuum.sim.h1-1e\") # Emulator target that will run the program with hardware-modeled noise\n",
        "                                            # Uses HQC/quota\n",
        "qsharp.azure.target_capability(\"AdaptiveExecution\")\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "nteract": {
          "transient": {
            "deleting": false
          }
        }
      },
      "source": [
        "## 2. Compile the RUS Program\n",
        "<i>Note: compiling this code will produce expected warnings about potentially incompatible capabilities from the utility operation `PreparePauliEigenstate`. The incompatible code paths in the library are not used by this sample and the warning can be safely ignored.</i>"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "jupyter": {
          "outputs_hidden": false,
          "source_hidden": false
        },
        "microsoft": {
          "language": "qsharp"
        },
        "nteract": {
          "transient": {
            "deleting": false
          }
        },
        "vscode": {
          "languageId": "qsharp"
        }
      },
      "outputs": [],
      "source": [
        "%%qsharp\n",
        "open Microsoft.Quantum.Intrinsic;\n",
        "open Microsoft.Quantum.Canon;\n",
        "open Microsoft.Quantum.Math;\n",
        "open Microsoft.Quantum.Preparation;\n",
        "open Microsoft.Quantum.Diagnostics;\n",
        "\n",
        "/// # Summary\n",
        "/// Example of a Repeat-until-success algorithm implementing a circuit\n",
        "/// that achieves exp(i*ArcTan(2)*Z), also known as the \"V gate\"\n",
        "/// by Paetznick & Svore.\n",
        "///\n",
        "/// # References\n",
        "/// - [ *Adam Paetznick, Krysta M. Svore*,\n",
        "/// Quantum Information & Computation 14(15 & 16): 1277-1301 (2014)\n",
        "/// ](https://arxiv.org/abs/1311.1074)\n",
        "/// For circuit diagram, see file RUS.png.\n",
        "///\n",
        "/// # Input\n",
        "/// ## inputValue\n",
        "/// Boolean value for input qubit (true maps to One, false maps to Zero)\n",
        "/// ## inputBasis\n",
        "/// Pauli basis in which to prepare input qubit\n",
        "/// ## limit\n",
        "/// Integer limit to number of repeats of circuit\n",
        "///\n",
        "/// # Remarks\n",
        "/// The program executes a circuit on a \"target\" qubit using an \"auxiliary\"\n",
        "/// and \"resource\" qubit. The circuit consists of two parts (red and blue\n",
        "/// in image).\n",
        "/// The goal is to measure Zero for both the auxiliary and resource qubit.\n",
        "/// If this succeeds, the program will have effectively applied an\n",
        "/// Rz(arctan(2)) gate (also known as V_3 gate) on the target qubit.\n",
        "/// If this fails, the program reruns the circuit up to <limit> times.\n",
        "operation AllocateQubitsAndApplyRzArcTan2 (\n",
        "    inputValue : Bool,\n",
        "    inputBasis : Pauli,\n",
        "    measurementBasis : Pauli,\n",
        "    limit : Int\n",
        ") : Result[] {\n",
        "    use (auxiliary, resource, target) = (Qubit(), Qubit(), Qubit());\n",
        "    \n",
        "    // Prepare target qubit in a zero- or one-state, based on input value\n",
        "    if (inputValue) {\n",
        "        X(target);\n",
        "    }\n",
        "    PreparePauliEigenstate(inputBasis, target);\n",
        "    \n",
        "    within {\n",
        "        H(auxiliary);\n",
        "        H(resource);\n",
        "    }\n",
        "    apply {\n",
        "        ApplyRzArcTan2(limit, auxiliary, resource, target);\n",
        "\n",
        "        // let rotation angle = 2.0 * ArcTan(2.0);\n",
        "        let rotationAngle =\n",
        "        2.2142974355881810060341309203570740801400952908028652933530784148;\n",
        "        Rz(rotationAngle, target); // Rotate back to initial state\n",
        "    }\n",
        "    \n",
        "    return [M(auxiliary), M(resource), Measure([measurementBasis], [target])];\n",
        "}\n",
        "\n",
        "/// # Summary\n",
        "/// Apply Rz(arctan(2)) on qubits using repeat until success algorithm.\n",
        "/// Updated to use for-loop sytle.\n",
        "operation ApplyRzArcTan2 (\n",
        "    limit : Int,\n",
        "    auxiliary : Qubit,\n",
        "    resource : Qubit,\n",
        "    target : Qubit\n",
        ") : Unit {\n",
        "    mutable (result1, result2) = (false, false);\n",
        "    \n",
        "    // Run Part 1 of the program.\n",
        "    for _ in 1..limit {\n",
        "        if not result1 or not result2 {\n",
        "            set result1 = ApplyAndMeasurePart1(auxiliary, resource) == Zero;\n",
        "            \n",
        "            // We’ll only run Part 2 if Part 1 returns Zero.\n",
        "            // Otherwise, we’ll skip and rerun Part 1 again.\n",
        "            if result1 {\n",
        "                set result2 = ApplyAndMeasurePart2(resource, target) == Zero;\n",
        "                \n",
        "                if not result2 {\n",
        "                    Z(resource); // Reset resource\n",
        "                    Adjoint Z(target); // Correct effective Z rotation on target\n",
        "                }\n",
        "            } else {\n",
        "                Z(auxiliary);\n",
        "                Reset(resource);\n",
        "                H(resource);\n",
        "            }\n",
        "        }\n",
        "    }\n",
        "}\n",
        "\n",
        "/// # Summary\n",
        "/// Apply part 1 of RUS circuit and measure\n",
        "/// auxiliary qubit in Pauli X basis\n",
        "operation ApplyAndMeasurePart1(auxiliary : Qubit, resource : Qubit) : Result {\n",
        "    within {\n",
        "        T(auxiliary);\n",
        "    } \n",
        "    apply {\n",
        "        CNOT(resource, auxiliary);\n",
        "    }\n",
        "    return Measure([PauliX], [auxiliary]);\n",
        "}\n",
        "\n",
        "/// # Summary\n",
        "/// Apply part 2 of RUS circuit and measure\n",
        "/// resource qubit in Pauli X basis\n",
        "operation ApplyAndMeasurePart2(resource : Qubit, target : Qubit) : Result {\n",
        "    T(target);\n",
        "    Z(target);\n",
        "    CNOT(target, resource);\n",
        "    T(resource);\n",
        "    return Measure([PauliX], [resource]);\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "nteract": {
          "transient": {
            "deleting": false
          }
        }
      },
      "source": [
        "## 3. Setup the Experiment\n",
        "We create three wrapper operations for the code above, each one increasting the number of allowed retries compared to the previous one, so we can see the percentage of resulting success when the repeat logic is allowed to execute."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "jupyter": {
          "outputs_hidden": false,
          "source_hidden": false
        },
        "nteract": {
          "transient": {
            "deleting": false
          }
        }
      },
      "outputs": [],
      "source": [
        "# We declare the functions we will define in Q# as a callable so that Python recognizes the symbols,\n",
        "# then define those functions calling code from the algorithm above.\n",
        "TestRUSLimit0: any = None\n",
        "TestRUSLimit1: any = None\n",
        "TestRUSLimit2: any = None"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "jupyter": {
          "outputs_hidden": false,
          "source_hidden": false
        },
        "microsoft": {
          "language": "qsharp"
        },
        "nteract": {
          "transient": {
            "deleting": false
          }
        },
        "vscode": {
          "languageId": "qsharp"
        }
      },
      "outputs": [],
      "source": [
        "%%qsharp\n",
        "\n",
        "/// # Summary\n",
        "/// Test the RzArcTan2 algorithm using Pauli-X for preparation and measurement,\n",
        "/// with no repeat retries.\n",
        "operation TestRUSLimit0() : Result[] {\n",
        "    return AllocateQubitsAndApplyRzArcTan2(false, PauliX, PauliX, 0);\n",
        "}\n",
        "\n",
        "/// # Summary\n",
        "/// Test the RzArcTan2 algorithm using Pauli-X for preparation and measurement,\n",
        "/// using a limit of 1 looping retries.\n",
        "operation TestRUSLimit1() : Result[] {\n",
        "    return AllocateQubitsAndApplyRzArcTan2(false, PauliX, PauliX, 1);\n",
        "}\n",
        "\n",
        "/// # Summary\n",
        "/// Test the RzArcTan2 algorithm using Pauli-X for preparation and measurement,\n",
        "/// using a limit of 2 looping retries.\n",
        "operation TestRUSLimit2() : Result[] {\n",
        "    return AllocateQubitsAndApplyRzArcTan2(false, PauliX, PauliX, 2);\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "nteract": {
          "transient": {
            "deleting": false
          }
        }
      },
      "source": [
        "## 4. Run the Experiment\n",
        "We can now submit and wait on each of the above experiments, displaying the resulting histograms and saving them into variables for later analysis."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "jupyter": {
          "outputs_hidden": false,
          "source_hidden": false
        },
        "nteract": {
          "transient": {
            "deleting": false
          }
        }
      },
      "outputs": [],
      "source": [
        "job0 = qsharp.azure.submit(TestRUSLimit0, jobName=\"RUS Limit 0\", shots=100)\n",
        "while (job0.status not in [\"Succeeded\", \"Failed\", \"Cancelled\"]):\n",
        "    print(\".\", end=\"\", flush=True)\n",
        "    time.sleep(5)\n",
        "    job0 = qsharp.azure.status()\n",
        "results0 = qsharp.azure.output()\n",
        "results0"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "jupyter": {
          "outputs_hidden": false,
          "source_hidden": false
        },
        "nteract": {
          "transient": {
            "deleting": false
          }
        }
      },
      "outputs": [],
      "source": [
        "job1 = qsharp.azure.submit(TestRUSLimit1, jobName=\"RUS Limit 1\", shots=100)\n",
        "while (job1.status not in [\"Succeeded\", \"Failed\", \"Cancelled\"]):\n",
        "    print(\".\", end=\"\", flush=True)\n",
        "    time.sleep(5)\n",
        "    job1 = qsharp.azure.status()\n",
        "results1 = qsharp.azure.output()\n",
        "results1"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "jupyter": {
          "outputs_hidden": false,
          "source_hidden": false
        },
        "nteract": {
          "transient": {
            "deleting": false
          }
        }
      },
      "outputs": [],
      "source": [
        "job2 = qsharp.azure.submit(TestRUSLimit2, jobName=\"RUS Limit 2\", shots=100)\n",
        "while (job2.status not in [\"Succeeded\", \"Failed\", \"Cancelled\"]):\n",
        "    print(\".\", end=\"\", flush=True)\n",
        "    time.sleep(5)\n",
        "    job2 = qsharp.azure.status()\n",
        "results2 = qsharp.azure.output()\n",
        "results2"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "nteract": {
          "transient": {
            "deleting": false
          }
        }
      },
      "source": [
        "## 5. Plot the Results\n",
        "Finally, we plot the results. When run against the emulator or hardware, each successive experiment should show increasing probability of success, indicating that the more allowed runs of RUS further refine the effectiveness of the program."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "jupyter": {
          "outputs_hidden": false,
          "source_hidden": false
        },
        "nteract": {
          "transient": {
            "deleting": false
          }
        }
      },
      "outputs": [],
      "source": [
        "from matplotlib import pyplot\n",
        "\n",
        "success = \"[0, 0, 0]\"\n",
        "xticks = [0, 1, 2]\n",
        "pyplot.title(\"Probability Success\")\n",
        "pyplot.plot(xticks, [results0[success], results1[success], results2[success]])\n",
        "pyplot.xticks([0, 1, 2])\n",
        "pyplot.xlabel(\"Repeat Limit\")\n",
        "pyplot.ylabel(\"Probability\")\n",
        "\n",
        "\n",
        "pyplot.show()"
      ]
    }
  ],
  "metadata": {
    "kernel_info": {
      "name": "python3"
    },
    "kernelspec": {
      "display_name": "Python 3 (ipykernel)",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.9.18"
    },
    "nteract": {
      "version": "nteract-front-end@1.0.0"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
